#include "refine/bit_mask.h"
#include "refine/refine2.h"
#include <imglib/imageclass.h>
#include <imglib/bitmap.h>
#include <imglib/bmpmorph.h>
#include <imglib/pyramid.h>
#include <iostream>
#include <limits>
using std::clog;
using std::endl;

namespace refine {

namespace refine2 {

params::params()
{
	max_motion = 5;
	max_level = 3;
	silent = false;
}

/// builds ribbon map of appropriate width around bound in mask
static void ribbon(mask const & m, int w, mask & r)
{
	mask erd;
	img::erode4(erd, m, w);
	img::dilate4(r, m, w);
	img::combine(r, erd, img::bit_and_not());
}

void track(
	const byte_image & ref_im, const mask & ref_m, 
	const byte_image & tgt_im, mask & tgt_m, 
	const params & p
)
{
	assert (p.max_motion > 0);
	std::vector<int> width;
	for (int m = p.max_motion; m > 0 && width.size() <= p.max_level; m /= 2)
		width.push_back(m);
	int pyramid_levels = width.size() - 1;

	byte_image dref_im;
	img::downsample(ref_im, dref_im, 1 << pyramid_levels);
	mask dref_m;
	img::downsample(ref_m, dref_m, 1 << pyramid_levels);

	img::pyramid<byte_image> tgt_im_pyramid(tgt_im, pyramid_levels, img::not_copy_original);
	img::pyramid<mask> tgt_m_pyramid(tgt_m, pyramid_levels, img::not_copy_original);
	mask dtgt_m = tgt_m_pyramid[pyramid_levels];

	bit_mask::params bp;
	bp.whs = 5;
	bp.auto_t = true;
	bp.t = 3.5f;
	mask nearbound;
	bp.modifiable = &nearbound;
	bp.silent = p.silent;

	//topmost level of pyramid: reference frame tracking
	ribbon(tgt_m_pyramid[pyramid_levels], width[pyramid_levels], nearbound);
	bit_mask::track(
		dref_im, dref_m, 
		tgt_im_pyramid[pyramid_levels], dtgt_m, 
		source_reference, 0, bp);

	bp.auto_t = false;

	//descend in tgt-pyramid and use target frame refine at each level
	for (int level = pyramid_levels - 1; level >= 0; --level) 
	{
		ribbon(tgt_m_pyramid[level], width[level], nearbound);

		mask m(tgt_im_pyramid[level].dim());
		m.fill(false);
		img::upsample(dtgt_m, m, 2);
		img::combine(m, nearbound, img::bit_and());

		dtgt_m = tgt_m_pyramid[level];
		img::combine(dtgt_m, nearbound, img::bit_and_not());
		img::combine(dtgt_m, m, img::bit_or());

		bit_mask::adjust(tgt_im_pyramid[level], dtgt_m, bp);
	}

	assert (dtgt_m.dim() == tgt_m.dim());
	tgt_m.swap(dtgt_m);
}

} //namespace refine2

} //namespace refine
